﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using Metis.Share;

namespace Metis.Controls
{
    internal class SplitAdorner: Adorner
    {
        #region Variables

        readonly VisualCollection _visualChildren;
        private readonly double _handlerSize;       //Handler size
        private readonly Thumb _top;                //Handlers
        private readonly Thumb _bottom;             //Handlers
        private Point _topPos, _bottomPos;          //TopLeft points for thumb handlers

        #endregion

        #region Constructor

        public SplitAdorner(UIElement adornedElement) : base(adornedElement)
        {
            #region Bindings

            BindingOperations
                .SetBinding(this, MiddleProperty, new Binding
                {
                    Path = new PropertyPath("List/Middle"), //TODO: There shouldn't be any hardcoding here
                    UpdateSourceTrigger =
                        UpdateSourceTrigger.PropertyChanged,
                        Mode = BindingMode.TwoWay
                });

            BindingOperations
                .SetBinding(this, ThetaProperty, new Binding
                {
                    Path = new PropertyPath("List/Theta"), //TODO: There shouldn't be any hardcoding here
                    UpdateSourceTrigger =
                        UpdateSourceTrigger.PropertyChanged,
                        Mode = BindingMode.TwoWay
                });

            #endregion

            _visualChildren = new VisualCollection(this);
            _handlerSize = 80; // TODO: To AdornedElement DP 

            _top = new Thumb
                       {
                           Cursor = Cursors.Hand,
                           Background = new SolidColorBrush(Colors.Red), //Color should be able to get changed by user
                           Height = _handlerSize,
                           Width = _handlerSize
                       };

            _bottom = new Thumb
                          {
                              Cursor = Cursors.Hand,
                              Background = new SolidColorBrush(Colors.Red), //TODO: Color should be able to get changed by user 
                              Height = _handlerSize,
                              Width = _handlerSize
                          };

            _topPos = new Point((double)GetValue(MiddleProperty) - _handlerSize / 2, -_handlerSize / 2);
            _bottomPos = new Point((double) GetValue(MiddleProperty) - _handlerSize/2,
                                   adornedElement.DesiredSize.Height - _handlerSize / 2);

            _visualChildren.Add(_top);
            _visualChildren.Add(_bottom);

            _top.DragDelta += HandleTop;
            _bottom.DragDelta += HandleBottom;
        }

        #endregion

        #region Overrides

        protected override void OnRender(DrawingContext drawingContext)
        {
            drawingContext.DrawLine(
                new Pen(Brushes.Red, 4), //TODO: Line width to variable, color should be able to get changed by user
                    new Point(_topPos.X + _handlerSize / 2, _topPos.Y + _handlerSize / 2),
                    new Point(_bottomPos.X + _handlerSize / 2, AdornedElement.DesiredSize.Height)
                    );

            _bottomPos.Y = AdornedElement.DesiredSize.Height - _handlerSize / 2;

            var leftPoly = new List<Point>
                                       {
                                           new Point(), // top left point
                                           new Point(0, AdornedElement.DesiredSize.Height), // bottom left point
                                           new Point(
                                               _bottomPos.X + _handlerSize / 2 - 2, // bottom right point TODO: Line width to variable
                                               AdornedElement.DesiredSize.Height),
                                           new Point(_topPos.X + _handlerSize / 2 - 2, 0), //top right point TODO: Line width to variable
                                           new Point() // and again top left point 
                                       };

            var rightPoly = new List<Point>
                                {
                                    new Point(_topPos.X + _handlerSize / 2 + 2, 0), //TODO: Line width to variable
                                    new Point(AdornedElement.DesiredSize.Width, 0),
                                    new Point(AdornedElement.DesiredSize.Width, AdornedElement.DesiredSize.Height),
                                    new Point(_bottomPos.X + _handlerSize / 2 + 2, AdornedElement.DesiredSize.Height), //TODO: Line width to variable
                                    new Point(_topPos.X + _handlerSize / 2 + 2, 0), //TODO: Line width to variable
                                };


            drawingContext.DrawGeometry(new SolidColorBrush(Color.FromArgb(80, 0, 180, 0)), null, //TODO: Color should be able to get changed by user
                                        Geometries.CreatePolygon(leftPoly));
            drawingContext.DrawGeometry(new SolidColorBrush(Color.FromArgb(80, 0, 0, 180)), null, //TODO: Color should be able to get changed by user
                                        Geometries.CreatePolygon(rightPoly));
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            double middle = (double)GetValue(MiddleProperty);
            double theta = (double) GetValue(ThetaProperty);

            double deltaX = (Math.Tan((Math.PI / 180) * theta)) * (AdornedElement.DesiredSize.Height / 2);
            _topPos = new Point(middle + deltaX - _handlerSize / 2, _topPos.Y);
            _bottomPos = new Point(middle - deltaX - _handlerSize / 2, _bottomPos.Y);

            _top.Arrange(new Rect(_topPos, new Size(_handlerSize, _handlerSize)));
            _bottom.Arrange(new Rect(_bottomPos, new Size(_handlerSize, _handlerSize)));
            return base.ArrangeOverride(finalSize);
        }

        #endregion

        #region Thumb events

        private void HandleTop(object sender, DragDeltaEventArgs e)
        {
            var hitThumb = sender as Thumb;
            if (hitThumb == null) return;

            double desiredWidth = AdornedElement.DesiredSize.Width;

            switch (Keyboard.Modifiers)
            {
                case ModifierKeys.Control:

                    if (_topPos.X + e.HorizontalChange + _handlerSize / 2 > 0 &&
                        _topPos.X + e.HorizontalChange + _handlerSize / 2 <= desiredWidth &&
                        _bottomPos.X + e.HorizontalChange + _handlerSize / 2 > 0 &&
                        _bottomPos.X + e.HorizontalChange + _handlerSize / 2 <= desiredWidth)
                    {
                        _topPos = new Point(_topPos.X + e.HorizontalChange, _topPos.Y);
                        Middle += e.HorizontalChange;
                        InvalidateVisual();
                    }

                    break;

                case ModifierKeys.None:
                    if (_topPos.X + e.HorizontalChange + _handlerSize/2 > 0 &&
                        _topPos.X + e.HorizontalChange + _handlerSize/2 <= desiredWidth)
                    {
                        _topPos = new Point(_topPos.X + e.HorizontalChange, _topPos.Y);
                        var oldTheta = Theta;
                        var newTheta = (Math.Atan(((_topPos.X - _bottomPos.X)/AdornedElement.DesiredSize.Height)))*180/
                                       Math.PI;
                        var x = (AdornedElement.DesiredSize.Height/2)*
                                (Math.Tan(newTheta*Math.PI/180) - Math.Tan(oldTheta*Math.PI/180));
                        Middle += x;
                        Theta = newTheta;
                        InvalidateVisual();
                    }
                    break;
            }
        }

        private void HandleBottom(object sender, DragDeltaEventArgs e)
        {
            var hitThumb = sender as Thumb;
            if (hitThumb == null) return;

            double desiredWidth = AdornedElement.DesiredSize.Width;

            switch (Keyboard.Modifiers)
            {
                case ModifierKeys.Control:

                    if (_topPos.X + e.HorizontalChange + _handlerSize / 2 > 0 &&
                        _topPos.X + e.HorizontalChange + _handlerSize / 2 <= desiredWidth &&
                        _bottomPos.X + e.HorizontalChange + _handlerSize / 2 > 0 &&
                        _bottomPos.X + e.HorizontalChange + _handlerSize / 2 <= desiredWidth)
                    {
                        _bottomPos = new Point(_bottomPos.X + e.HorizontalChange, _bottomPos.Y);
                        Middle += e.HorizontalChange;
                        InvalidateVisual();
                    }

                    break;

                case ModifierKeys.None:

                    if (_bottomPos.X + e.HorizontalChange + _handlerSize / 2 > 0 &&
                        _bottomPos.X + e.HorizontalChange + _handlerSize / 2 <= desiredWidth)
                    {
                        _bottomPos = new Point(_bottomPos.X + e.HorizontalChange, _bottomPos.Y);

                        var oldTheta = Theta;
                        var newTheta = (Math.Atan(((_topPos.X - _bottomPos.X) / AdornedElement.DesiredSize.Height))) * 180 / Math.PI;
                        var x = (AdornedElement.DesiredSize.Height / 2) *
                                (-Math.Tan(newTheta * Math.PI / 180) + Math.Tan(oldTheta * Math.PI / 180));
                        Middle += x;
                        Theta = newTheta;
                        InvalidateVisual();
                    }

                    break;
            }



        }

        #endregion

        #region DPs

        public static readonly DependencyProperty MiddleProperty =
            DependencyProperty
                .Register("Middle", typeof (double), typeof (SplitAdorner),
                          new PropertyMetadata(0.0, SetMiddle));

        private static void SetMiddle(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var element = (d as SplitAdorner);
            if (element != null)
            {
                element.Middle = (double)e.NewValue;
                element.InvalidateVisual();
            }
        }

        public double Middle
        {
            get { return (double) GetValue(MiddleProperty); }
            set { SetValue(MiddleProperty, value);}
        }

        public static readonly DependencyProperty ThetaProperty =
            DependencyProperty
                .Register("Theta", typeof (double), typeof (SplitAdorner),
                          new PropertyMetadata(0.0, SetTheta));
											   
        private static void SetTheta(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var element = (d as SplitAdorner);
            if (element != null)
            {
                element.SetValue(ThetaProperty, (double) e.NewValue);
                element.InvalidateVisual();
            }
        }

        public double Theta
        {
            get { return (double) GetValue(ThetaProperty); }
            set { SetValue(ThetaProperty, value); }
        }

        #endregion

        #region Stuff

        protected override int VisualChildrenCount { get { return _visualChildren.Count; } }
        protected override Visual GetVisualChild(int index) { return _visualChildren[index]; }

        #endregion
    }
}
